package com.lyncs.ods.modules.system;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONValidator;
import com.lyncs.ods.common.api.CommonResult;
import com.lyncs.ods.common.exception.ApiException;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.modules.msg.service.MessageService;
import com.lyncs.ods.modules.setting.model.CountryInfo;
import com.lyncs.ods.modules.setting.service.CountryInfoService;
import com.lyncs.ods.modules.setting.service.ShortLinkInfoService;
import com.lyncs.ods.resp.CardInfo;
import com.lyncs.ods.utils.CurrencyUtil;
import com.lyncs.ods.utils.IpUtils;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.regex.Pattern;

/**
 * @author alex
 * @date 2022/3/20 20:14
 * @description
 */
@RestController
@Api(tags = {"工具相关接口"})
@RequestMapping("tool")
@Slf4j
public class ToolController {

    @Autowired
    private MessageService messageService;
    @Autowired
    private CountryInfoService countryInfoService;
    @Autowired
    private ShortLinkInfoService shortLinkInfoService;
    @Value("${image.upload.path:/tmp/sku}")
    private String imagePath;
    @Value("${image.upload.nginx:}")
    private String imageSuffix;
    @Value("${file.upload.path:/tmp/file}")
    private String filePath;
    @Value("${file.upload.nginx:}")
    private String fileSuffix;

    private static final List<String> SUPPORT_TYPE = List.of("png", "jpg", "jpeg");
    private static final String IMG_REGEX = "(jpg|jpeg|png)";
    private static final Pattern IMG_PATTERN = Pattern.compile(IMG_REGEX);
    private static final String URL = "https://api.ooomn.com/api/ip?ip=206.71.50.230";

    @GetMapping("sms")
    @ApiOperation(value = "发送短信验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号码", dataType = "String", paramType = "query"),
    })
    public CommonResult<?> sendSms(String phone) {
        messageService.sendSmsCode(phone);
        return CommonResult.success();
    }

    @PostMapping("file/upload")
    @ApiOperation(value = "上传图片/文件")
    @ApiResponses(@ApiResponse(code = 200, message = "返回文件上传后的地址"))
    public CommonResult<String> upload(@RequestParam("file") MultipartFile file, @RequestHeader("X-Forwarded-Scheme") String scheme, HttpServletRequest request) throws IOException {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isEmpty(originalFilename)) {
            throw new ApiException("get origin file name failed, please try again");
        }
        boolean isImage = originalFilename.matches(IMG_REGEX);
        String fileType = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
        String path = isImage ? imagePath : filePath;
        String nginxSuffix = isImage ? imageSuffix : fileSuffix;
        String filePath = String.join(File.separator, path);
        if (!FileUtil.exist(filePath)) {
            FileUtil.mkdir(filePath);
        }
        String random = UUID.randomUUID().toString().replaceAll(LyncsOdsConstant.Common.MID_LINE, LyncsOdsConstant.Common.EMPTY);
        String suffix = String.join(File.separator, nginxSuffix, random + "." + fileType);
        FileUtil.writeBytes(file.getBytes(), String.join(File.separator, path, suffix));
        String httUrl = scheme + "://" + request.getServerName() + suffix;
        return CommonResult.success(httUrl);
    }

    @GetMapping("email")
    @ApiOperation(value = "发送邮箱验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "email", value = "收件人邮箱地址", dataType = "String", paramType = "query"),
    })
    public CommonResult<?> sendEmail1(String email) {
        if (!Validator.isEmail(email)) {
            throw new RuntimeException("invalid email");
        }
        messageService.sendEmailCode(email);
        return CommonResult.success();
    }

    @GetMapping("exchange")
    @ApiOperation(value = "汇率转换")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fromCurrency", value = "原货币", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "toCurrency", value = "目标货币", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "amount", value = "转换金额", dataType = "BigDecimal", paramType = "query"),
    })
    public CommonResult<BigDecimal> exchange(@RequestParam String fromCurrency, @RequestParam String toCurrency, @RequestParam BigDecimal amount) {
        return CommonResult.success(CurrencyUtil.exchange(fromCurrency, toCurrency, amount));
    }

    @GetMapping("ip2Country")
    @ApiOperation(value = "通过IP查询国家")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "ip", value = "ip地址，不传默认为客户端IP地址", dataType = "String", paramType = "query")
    })
    public CommonResult<CountryInfo> ip2Country(@RequestParam(value = "ip", required = false) String ip, HttpServletRequest request) {
        String regionCode = "CN";
        try {
            regionCode = StringUtils.isNotEmpty(ip) ? IpUtils.getCountryCode(ip) : IpUtils.getCountryCode(request);
        } catch (Exception e) {
            log.info("IpUtils.getCountryCode failed", e);
        }
        CountryInfo countryInfo = countryInfoService.lambdaQuery().eq(CountryInfo::getCode2, regionCode).last(" limit 1").one();
        return CommonResult.success(countryInfo);
    }

    @GetMapping("card2Bin")
    @ApiOperation(value = "通过银行卡号获取开户行信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "number", value = "银行卡号", dataType = "String", paramType = "query")
    })
    public CommonResult<CardInfo> card2Bin(@RequestParam(value = "number") String number) {
        JSONObject data = getXBroncResult("https://xbronc.com/freeapi/cardBin?api_key=&pan=" + number);
        return CommonResult.success(JSONObject.parseObject(data.toJSONString(), CardInfo.class));
    }

    @GetMapping("sms/verify")
    @ApiOperation(value = "验证短信验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "phone", value = "手机号码", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", dataType = "String", paramType = "query"),
    })
    public CommonResult<Boolean> verifySmsCode(@RequestParam(value = "phone") String phone,
                                               @RequestParam(value = "code") String code) {
        return CommonResult.success(messageService.verifySmsCode(phone, code));
    }

    @GetMapping("email/verify")
    @ApiOperation(value = "验证邮箱验证码")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "email", value = "邮箱", dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "code", value = "验证码", dataType = "String", paramType = "query"),
    })
    public CommonResult<Boolean> verifyEmailCode(@RequestParam(value = "email") String email,
                                                 @RequestParam(value = "code") String code) {
        return CommonResult.success(messageService.verifyEmailCode(email, code));
    }

    @GetMapping("link/generate")
    @ApiOperation(value = "生成短链")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "url", value = "url", dataType = "String", paramType = "query"),

    })
    public CommonResult<String> generateShortLink(@RequestParam(value = "url") String url) {
        /*LyncsOdsConstant.TxnType txnType = Arrays.stream(LyncsOdsConstant.TxnType.values()).filter(t -> type.equals(t.getValue())).findFirst().orElse(null);
        if (Objects.isNull(txnType)) {
            throw new ApiException("invalid type of " + type);
        }*/
        return CommonResult.success(shortLinkInfoService.generateShortLink(url));
    }

    @GetMapping("link/get")
    @ApiOperation(value = "获取完整链接")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "key", value = "key", dataType = "String", paramType = "query"),
    })
    public CommonResult<String> getCompleteLink(@RequestParam(value = "key") String key) {
        return CommonResult.success(shortLinkInfoService.getLinkByKey(key));
    }


    private JSONObject getXBroncResult(String url) {
        JSONObject result = new JSONObject();
        String ret = HttpUtil.get(url);
        log.info("get data from xbronc.com, url:{},ret:{}", url, ret);
        if (StringUtils.isEmpty(ret) || !JSONValidator.from(ret).validate()) {
            return result;
        }
        JSONObject retJson = JSONObject.parseObject(ret);
        if (retJson.getInteger("code") != 0 || !retJson.containsKey("data")) {
            return result;
        }
        return retJson.getJSONObject("data");
    }
}
